package com.jumi.microservice.stock.service.impl;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.google.common.collect.Lists;
import com.jumi.microservice.common.base.dto.ResponseResult;
import com.jumi.microservice.common.constant.*;
import com.jumi.microservice.common.exception.ExceptionEnum;
import com.jumi.microservice.common.utils.DateUtil;
import com.jumi.microservice.common.utils.StringProvider;
import com.jumi.microservice.material.dto.JmUnitResponse;
import com.jumi.microservice.material.dto.supplier.JmSupplierResponse;
import com.jumi.microservice.material.dto.warehouse.JmWarehouseResponse;
import com.jumi.microservice.material.mapper.JmGoodsMapper;
import com.jumi.microservice.material.service.JmWarehouseService;
import com.jumi.microservice.stock.domain.*;
import com.jumi.microservice.stock.mapper.*;
import com.jumi.microservice.stock.service.CommonService;
import com.jumi.microservice.stock.service.StockService;
import com.jumi.microservice.stock.service.StockTransferService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * @Description
 * @ClassName StockTransferServiceImpl
 * @Author Abel Yang
 * @Date 2020/9/11/011 14:11
 **/
@Service
@Transactional(rollbackFor = Exception.class)
public class StockTransferServiceImpl implements StockTransferService {

    private static final Logger logger = LoggerFactory.getLogger(StockServiceImpl.class);

    @Resource
    private CommonService commonService;

    @Resource
    private StockService stockService;

    @Resource
    private JmWarehouseService jmWarehouseService;

    @Resource
    private StockTransferMapper stockTransferMapper;

    @Resource
    private StockTransferDetailMapper stockTransferDetailMapper;

    @Resource
    private StockCheckLogMapper stockCheckLogMapper;

    @Resource
    private StockGoodsMapper stockGoodsMapper;

    @Resource
    private StockMaterialMapper stockMaterialMapper;
    @Resource
    private StockLogMapper stockLogMapper;

    @Resource
    private JmGoodsMapper goodsMapper;

    @Override
    public Boolean addTransfer(StockTransferApplyDTO apply, HttpServletRequest request) {

        //插入申请主表
        StockTransferDO transfer = new StockTransferDO();
        transfer.setGoodsId(apply.getGoodsId());
        transfer.setWarehouseId(apply.getWarehouseId());
        transfer.setToWarehouseId(apply.getToWarehouseId());
        transfer.setTransferTime(Objects.requireNonNull(DateUtil.str2TimeStamp(apply.getTransferTimeStr(), "yyyy-MM-dd HH:mm:ss")).intValue());
        transfer.setTransferRemark(apply.getTransferRemark());
        //总调货数
        transfer.setTotalTransferNum(apply.getTransferApplyDetailList().stream().filter(k -> null != k.getTransferNum()).mapToInt(StockTransferApplyDetailDTO::getTransferNum).sum());
        transfer.setUpdateBy(request.getHeader(RequestConstant.ADMIN_NAME));
        transfer.setCreateBy(request.getHeader(RequestConstant.ADMIN_NAME));
        stockTransferMapper.insert(transfer);

        //插入申请详情
        apply.getTransferApplyDetailList().forEach(applyDetail -> {
            //申请详情
            StockTransferDetailDO detailDO = new StockTransferDetailDO();
            detailDO.setTransferId(transfer.getId());
            detailDO.setMaterialId(applyDetail.getMaterialId());
            detailDO.setMaterialCode(applyDetail.getMaterialCode());
            detailDO.setGoodsId(apply.getGoodsId());
            detailDO.setTransferNum(applyDetail.getTransferNum());
            detailDO.setUpdateBy(request.getHeader(RequestConstant.ADMIN_NAME));
            detailDO.setCreateBy(request.getHeader(RequestConstant.ADMIN_NAME));
            stockTransferDetailMapper.insert(detailDO);
        });

        return true;
    }

    @Override
    public List<StockTransferVO> getTransferList(StockTransferSearchDTO stockTransferSearchDTO) {

        List<StockTransferVO> stockTransferList = stockTransferMapper.getTransferList(stockTransferSearchDTO);

        //仓库
        List<JmWarehouseResponse> warehouseResponseList = jmWarehouseService.getWarehouseList();
        Map<Long, String> warehouseMap = warehouseResponseList.stream().collect(Collectors.toMap(JmWarehouseResponse::getWarehouseId, JmWarehouseResponse::getWarehouseName, (k1, k2) -> k2));

        //查询商品单位
        Map<Integer, JmUnitResponse> unitMap = commonService.getUnitMapByIds(stockTransferList.stream().map(StockTransferVO::getUnitId).collect(Collectors.toList()));
        stockTransferList.forEach(stock -> {
            JmUnitResponse unitInfo = null != unitMap.get(stock.getUnitId()) ? unitMap.get(stock.getUnitId()) : new JmUnitResponse();
            stock.setUnit(StringProvider.isNotEmpty(unitInfo.getSmunitName()) ? unitInfo.getSmunitName() : "");

            stock.setWarehouseName(StringProvider.isNotEmpty(warehouseMap.get(stock.getWarehouseId())) ? warehouseMap.get(stock.getWarehouseId()) : "");
            stock.setToWarehouseName(StringProvider.isNotEmpty(warehouseMap.get(stock.getToWarehouseId())) ? warehouseMap.get(stock.getToWarehouseId()) : "");

            String checkTimeStr = stock.getCheckTime() != 0 ? DateUtil.time2String(stock.getCheckTime().toString(), null) : "";
            stock.setCheckTimeStr(checkTimeStr);
        });
        return stockTransferList;
    }

    @Override
    public StockTransferDetailVO getTransferDetail(Long transferId) {

        StockTransferDetailVO result = stockTransferMapper.getTransferGoodsById(transferId);
        if (null == result) {
            return null;
        }

        //单位
        Map<Integer, JmUnitResponse> unitMap = commonService.getUnitMapByIds(Lists.newArrayList(result.getUnitId()));
        JmUnitResponse unitResponse = null != unitMap.get(result.getUnitId()) ? unitMap.get(result.getUnitId()) : new JmUnitResponse();

        Map<Long, JmSupplierResponse> supplierMap = commonService.getSupplierMapByIds(Lists.newArrayList(result.getSupplierId()));
        JmSupplierResponse supplierResponse = null != supplierMap.get(result.getSupplierId()) ? supplierMap.get(result.getSupplierId()) : new JmSupplierResponse();

        //物料详情
        List<StockTransferDetailDTO> details = stockTransferDetailMapper.getDetailByTransferId(transferId);
        if (details.size() == 0) {
            return result;
        }

        for (StockTransferDetailDTO detail : details) {
            detail.setUnit(StringProvider.isNotEmpty(unitResponse.getSmunitName()) ? unitResponse.getSmunitName() : "");
        }

        result.setSupplierCompanyName(StringProvider.isNotEmpty(supplierResponse.getSupplierCompanyName()) ? supplierResponse.getSupplierCompanyName() : "");
        result.setTransferDetailList(details);
        return result;
    }

    @Override
    public Boolean editTransfer(StockTransferApplyDTO applyDTO, HttpServletRequest request) {
        StockTransferDO transferDO = stockTransferMapper.selectById(applyDTO.getTransferId());
        if (null == transferDO) {
            return false;
        }

        transferDO.setWarehouseId(applyDTO.getWarehouseId());
        transferDO.setToWarehouseId(applyDTO.getToWarehouseId());
        transferDO.setTransferTime(Objects.requireNonNull(DateUtil.str2TimeStamp(applyDTO.getTransferTimeStr(), "yyyy-MM-dd HH:mm:ss")).intValue());
        transferDO.setTransferRemark(applyDTO.getTransferRemark());
        transferDO.setCheckStatus((byte)0);
        //总调货数
        Integer totalTransferNum = applyDTO.getTransferApplyDetailList().stream().map(StockTransferApplyDetailDTO::getTransferNum).reduce(0, Integer::sum);
        transferDO.setTotalTransferNum(totalTransferNum);

        transferDO.setUpdateBy(request.getHeader(RequestConstant.ADMIN_NAME));
        stockTransferMapper.updateById(transferDO);

        List<StockTransferDetailDO> detailList = stockTransferDetailMapper.selectList(
                Wrappers.<StockTransferDetailDO>lambdaQuery()
                        .select(StockTransferDetailDO::getId)
                        .eq(StockTransferDetailDO::getIsDel, IsDeletedEnum.NO)
                        .eq(StockTransferDetailDO::getTransferId, applyDTO.getTransferId())
        );
        if (detailList.size() == 0) {
            return false;
        }
        List<Long> detailIds = detailList.stream().map(StockTransferDetailDO::getId).collect(Collectors.toList());
        applyDTO.getTransferApplyDetailList().forEach(detail -> {
            StockTransferDetailDO detailDO = new StockTransferDetailDO();
            detailDO.setTransferNum(detail.getTransferNum());
            detailDO.setUpdateBy(request.getHeader(RequestConstant.ADMIN_NAME));
            if (detailIds.contains(detail.getTransferDetailId())) {
                detailDO.setId(detail.getTransferDetailId());
                stockTransferDetailMapper.updateById(detailDO);
            } else {
                detailDO.setTransferId(applyDTO.getTransferId());
                detailDO.setMaterialId(detail.getMaterialId());
                detailDO.setMaterialCode(detail.getMaterialCode());
                detailDO.setGoodsId(applyDTO.getGoodsId());
                detailDO.setCreateBy(request.getHeader(RequestConstant.ADMIN_NAME));
                stockTransferDetailMapper.insert(detailDO);
            }
        });
        return true;
    }

    @Override
    public Boolean auditTransfer(StockTransferAuditDTO auditDTO, HttpServletRequest request) {
        Integer currentTime = Objects.requireNonNull(DateUtil.str2TimeStamp(DateUtil.getTime(), "yyyy-MM-dd HH:mm:ss")).intValue();

        auditDTO.getTransferIds().forEach(transferId -> {
            StockTransferDO stockTransfer = stockTransferMapper.selectById(transferId);
            stockTransfer.setCheckStatus(auditDTO.getCheckStatus());
            stockTransfer.setCheckTime(currentTime);
            stockTransfer.setCheckName(request.getHeader(RequestConstant.ADMIN_NAME));
            stockTransfer.setUpdateBy(request.getHeader(RequestConstant.ADMIN_NAME));
            stockTransfer.setCheckRemark(auditDTO.getCheckRemark());

            //审核操作
            int updateIds = stockTransferMapper.updateById(stockTransfer);
            logger.info("---------审核操作----[updateIds]:[{}]", JSON.toJSONString(updateIds));
            //添加审核日志
            StockCheckLogDO checkLog = new StockCheckLogDO();
            checkLog.setApplyId(transferId);
            checkLog.setCheckType(StockTransferTypeEnum.TYPE_BETWEEN_WAREHOUSE.getType());
            checkLog.setTotalNum(stockTransfer.getTotalTransferNum());
            checkLog.setCheckStatus(auditDTO.getCheckStatus());
            checkLog.setCheckName(request.getHeader(RequestConstant.ADMIN_NAME));
            checkLog.setCheckRemark(auditDTO.getCheckRemark());
            checkLog.setCreateBy(request.getHeader(RequestConstant.ADMIN_NAME));
            checkLog.setUpdateBy(request.getHeader(RequestConstant.ADMIN_NAME));
            stockCheckLogMapper.insert(checkLog);

            //通过
            if (StockCheckStatusEnum.STATUS_CHECKED.getStatus().equals(auditDTO.getCheckStatus())) {
                //改变仓库库存
                changeStock(stockTransfer);
            }
            logger.info("---------审核操作----[return]:[{}]", JSON.toJSONString("完成"));
        });
        return true;
    }

    /**
     * @Description:
     * @Param transfer
     * @Return
     * @Throws
     * @Author Abel Yang
     * @Date 2020/10/14/014 10:31
     */
    private void changeStock(StockTransferDO transfer) {
        //查询调货申请详情
        List<StockTransferDetailDO> details = stockTransferDetailMapper.selectList(
                Wrappers.<StockTransferDetailDO>lambdaQuery().eq(StockTransferDetailDO::getIsDel, IsDeletedEnum.NO)
                        .eq(StockTransferDetailDO::getTransferId, transfer.getId())
        );
        //仓库库存出库
        //outStockChange(details, transfer);
        //仓库库存入库
        inStockChange(details, transfer);
    }

    /**
     * @Description: 仓库库存出库
     * @Param details
     * @Param transfer
     * @Return
     * @Throws
     * @Author Abel Yang
     * @Date 2020/10/13/013 15:30
     */
    private void outStockChange(List<StockTransferDetailDO> transferDetails, StockTransferDO transfer) {
        //物料遍历出库存
        transferDetails.forEach(detail -> {
            //查询物料库存记录
            StockMaterialDO stockMaterial = stockMaterialMapper.selectOne(
                    Wrappers.<StockMaterialDO>lambdaQuery()
                            .eq(StockMaterialDO::getMaterialId, detail.getMaterialId())
                            .eq(StockMaterialDO::getWarehouseId, transfer.getWarehouseId())
                            .eq(StockMaterialDO::getIsDel, IsDeletedEnum.NO)
            );
            ExceptionEnum.FAIL_STOCK_MATERIAL_NOT_EXISTS.doThrowIf(null == stockMaterial);
            logger.info("调拨申请出库----stockMaterial: [{}]", JSON.toJSONString(stockMaterial));
            logger.info("调拨申请出库----detail: [{}]", JSON.toJSONString(detail));
            //可用库存校验
            assert stockMaterial != null;
            if (stockMaterial.getAvailableStockNum() - detail.getTransferNum() < 0) {
                ExceptionEnum.FAIL_STOCK_AVAILABLE_STOCK_NOT_ENOUGH.doThrowIf(true);
            }
            //入库库存校验
            if (stockMaterial.getRealStockNum() - detail.getTransferNum() < 0) {
                ExceptionEnum.FAIL_STOCK_REAL_STOCK_NOT_ENOUGH.doThrowIf(true);
            }
            //添加出库日志
            StockLogDO logDO = new StockLogDO();
            logDO.setMaterialId(detail.getMaterialId());
            logDO.setGoodsId(detail.getGoodsId());
            logDO.setWarehouseId(transfer.getWarehouseId());
            logDO.setChangeType(StockChangeTypeEnum.TYPE_TRANSFER_OUT.getChangeType());
            logDO.setChangeNum(detail.getTransferNum());
            logDO.setCreateBy(stockMaterial.getCreateBy());
            logDO.setOriginNum(stockMaterial.getRealStockNum());
            logDO.setChangeReason("调拨申请出库");
            stockLogMapper.insert(logDO);
            logger.info("调拨申请出库 [{}]", JSON.toJSONString(transfer));
            //物料出库
            String updateBys = !transfer.getUpdateBy().equals("") ? transfer.getUpdateBy() : transfer.getCreateBy();
            int updateNums = stockMaterialMapper.update(new StockMaterialDO(),
                    Wrappers.<StockMaterialDO>lambdaUpdate()
                            .setSql("in_stock_num = in_stock_num - " + detail.getTransferNum())
                            .setSql("available_stock_num = available_stock_num - " + detail.getTransferNum())
                            .setSql("out_stock_num = out_stock_num + " + detail.getTransferNum())
                            .setSql("real_stock_num = real_stock_num - " + detail.getTransferNum())
                            .set(StockMaterialDO::getUpdateBy, updateBys)
                            .eq(StockMaterialDO::getId, stockMaterial.getId())
            );
            logger.info("---------审核操作----[updateNums]:[{}]", JSON.toJSONString(updateNums));
        });
    }

    /**
     * @Description: 仓库库存入库
     * @Param details
     * @Param transfer
     * @Return
     * @Throws
     * @Author Abel Yang
     * @Date 2020/10/13/013 15:30
     */
    private void inStockChange(List<StockTransferDetailDO> details, StockTransferDO transfer) {
        StockDTO stock = new StockDTO();
        stock.setChangeType(StockChangeTypeEnum.TYPE_TRANSFER_IN.getChangeType());
        stock.setWarehouseId(transfer.getToWarehouseId());
        stock.setGoodsId(transfer.getGoodsId());
        stock.setUpdateBy(transfer.getCreateBy());
        stock.setInStockTotalNum(details.stream().mapToInt(StockTransferDetailDO::getTransferNum).sum());
        logger.info("---------审核操作----[transfer]:[{}]", JSON.toJSONString(transfer));
        List<StockDetailDTO> stockDetailDtoList = new ArrayList<>();
        details.forEach(detailDO -> {
            StockDetailDTO detailDTO = new StockDetailDTO();
            detailDTO.setMaterialId(detailDO.getMaterialId());
            detailDTO.setMaterialCode(detailDO.getMaterialCode());
            detailDTO.setInStockNum(detailDO.getTransferNum());
            stockDetailDtoList.add(detailDTO);
            stock.setStockDetailDtoList(stockDetailDtoList);
            logger.info("---------审核操作----[detailDO]:[{}]", JSON.toJSONString(detailDO));
            //添加出库日志
            //查询物料库存记录
            StockMaterialDO stockMaterial = stockMaterialMapper.selectOne(
                    Wrappers.<StockMaterialDO>lambdaQuery()
                            .eq(StockMaterialDO::getMaterialId, detailDO.getMaterialId())
                            .eq(StockMaterialDO::getWarehouseId, transfer.getToWarehouseId())
                            .eq(StockMaterialDO::getIsDel, IsDeletedEnum.NO)
            );
            StockMaterialDO stockMaterialDO = new StockMaterialDO();
            if(null == stockMaterial){
                stockMaterialDO.setRealStockNum(0);
            }else{
                stockMaterialDO.setRealStockNum(stockMaterial.getRealStockNum());
            }
            logger.info("---------审核操作----[stockMaterial]:[{}]", JSON.toJSONString(stockMaterial));
            StockLogDO logDO = new StockLogDO();
            logDO.setMaterialId(detailDO.getMaterialId());
            logDO.setGoodsId(detailDO.getGoodsId());
            logDO.setWarehouseId(transfer.getToWarehouseId());
            logDO.setChangeType(StockChangeTypeEnum.TYPE_TRANSFER_IN.getChangeType());
            logDO.setChangeNum(detailDO.getTransferNum());
            logDO.setCreateBy(transfer.getCreateBy());
            logDO.setOriginNum(stockMaterialDO.getRealStockNum());
            logDO.setChangeReason("调拨申请入库");
            logDO.setChangeQuantityType((byte)1);
            int insertLogs = stockLogMapper.insert(logDO);
        });
        logger.info("---------审核操作----[调拨申请入库]:[{}]", JSON.toJSONString(stock));
        stockService.inStock(stock);
    }
}
